<?php

abstract class GaAPI_Services_Abstract {

    protected $api;
    protected $_client;

    protected $_version = 'v200909';
    protected $_headersFilters = array();
    protected $_serviceName;
    protected $_services;
    protected $_serviceHeaders;

    public function setApi(GaAPI $api = null) {
        $this->api = $api;
    }


    public function getApi() {
        return $this->api;
    }


    /**
     * @return GaAPI_Clients_Abstract
     */
    public function getClient() {
        if (!$this->_client) {
            $class = 'GaAPI_Clients_' .  ucfirst($this->_version);
            GaAPI_Autoloader::instance()->load('GaAPI_Clients_Abstract');
            GaAPI_Autoloader::instance()->load($class);
            $this->_client = new $class;
            $this->_client->setMethod($this);
        }

        return $this->_client;
    }


    protected function getService() {
        $headers = $this->getClient()->getHeaders();
        $headersHash = sha1($headers);
        if (!$this->_services[$headersHash]) {
            if (empty($this->_serviceName)) {
                $this->throwError("Service name not provided.");
                return;
            }

            if (!class_exists('SoapClientFactory', false)) {
                require(GAAPI_DEPENDENCIES_PATH . '/soapclientfactory.php');
            }

            $service = SoapClientFactory::GetClient($this->getClient()->getRequestURL() . '/' . $this->_serviceName . '?wsdl', 'wsdl');
            $service->setHeaders($headers);
            $service->soap_defencoding = 'UTF-8';
            $this->_service[$headersHash] = $service;
        }

        return $this->_service[$headersHash];
    }


    protected function call($name, $params = false) {
        if ($params) {
            $response = $this->getService()->call($name, $params);
        } else {
            $response = $this->getService()->call($name);
        }

        $this->getApi()->resetCall();

        if ($this->getService()->fault) {
            $message  = 'Fault: '  . $this->getService()->fault . '<br />' . "\n";
            $message .= 'Code: '   . $this->getService()->faultcode . '<br />' . "\n";
            $message .= 'String: ' . $this->getService()->faultstring . '<br />' . "\n";
            $message .= 'Detail: ' . $this->getService()->faultdetail . '<br />' . "\n";
            $this->throwError($message);
        } elseif (!empty($response['faultcode'])) {
            $message  = 'Fault: '  . $response['faultstring'] . '<br />' . "\n";
            $message .= 'Code: '   . $response['faultcode'] . '<br />' . "\n";
            $this->throwError($message);
        }

        return $response;
    }

    public function mutate($operations) {
        $request_xml = '<mutate xmlns="' . $this->getClient()->getNamespace() . '">';
        if (!is_array($operations)) {
            $operations = array($operations);
        }

        foreach ($operations as $operation) {
            if (is_object($operation) && $operation instanceof GaAPI_Objects_Common_Operation) {
                $request_xml .= $operation;
            } else {
                $this->throwError('Operations must be instance of GaAPI_Objects_Common_Operation');
            }
        }
        $request_xml .= '</mutate>';
        echo htmlentities($request_xml);

        $return = $this->call('mutate', $request_xml);
        return $return['rval']['value'];
    }


    protected function getVersion() {
        $version = $this->_namespaceVersion;
        $versions = array_keys($this->api->getNamespaces());
        $version = (in_array($version, $versions)) ? $version : reset($versions);
        return $version;
    }

    protected function throwError($error_msg) {
        $this->api->throwError($error_msg);
    }


}